#pragma once

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
static const int defaultcap = 5; 

template <class T>
class RingQueue{
public:
    RingQueue(const int& cap =defaultcap) :_ringqueue(cap),_cap(cap)
    {
        sem_init(&_spacesem,0,_cap);
        sem_init(&_datasem,0,0);
        pthread_mutex_init(&_p_mutex,nullptr);
        pthread_mutex_init(&_c_mutex,nullptr);
        _consumerstep = _productorstep = 0;
    }

    void push(const T& inq){
        //申请信号量（申请space信号量）
        sem_wait(&_spacesem); //成功就继续，失败就阻塞
        pthread_mutex_lock(&_p_mutex);
        _ringqueue[_productorstep++] = inq;
        _productorstep%=_cap;
        pthread_mutex_unlock(&_p_mutex);
        sem_post(&_datasem); //此时V操作不能操作spacesem，因为数据还占有这个位置，而一个操作datasem
    }

    void pop(T* outq){
        sem_wait(&_datasem);
        pthread_mutex_lock(&_c_mutex);
        *outq = _ringqueue[_consumerstep++];
        _consumerstep%=_cap;
        pthread_mutex_unlock(&_c_mutex);
        sem_post(&_spacesem);

    }


    ~RingQueue(){
        sem_destroy(&_spacesem);
        sem_destroy(&_datasem);
        pthread_mutex_destroy(&_p_mutex);
        pthread_mutex_destroy(&_c_mutex);
    }


private:
    std::vector<T> _ringqueue; //使用数组模拟环形队列
    int _cap;
    sem_t _spacesem; //剩余空间信号量
    sem_t _datasem; // 剩余数据信号量
    pthread_mutex_t _p_mutex;
    pthread_mutex_t _c_mutex;
    int _productorstep;
    int _consumerstep;
};